Multiprocessing is the use of more than one processor (CPU) simultaneously. By definition only a machine with more than one CPU is capable of multiprocessing. Multitasking allows multiple streams of execution to be created even if there is only a single CPU. The MP API implements a multiprocessing and multitasking environment. Any number of streams of execution can be created and one stream per CPU can be executing at any particular instant in time. Each stream of execution is called a task. Having concurrent tasks working on parts of some job, e.g. a ray trace, an image filter, a fractal etc., can reduce the overall time it takes to complete the job.
What is the MP API?
The MP API allows a programmer to create tasks and to establish communication between them and the main application's cooperative task. A small number of other services are also available. Multiprocessing Services 2.1 document describes these services in detail.
What is the Multiprocessing API Library?
The Multiprocessing API Library is a shared library that provides the services defined in the MP API. The Multiprocessing API Library communicates with the integrated task scheduling facilities and other task related issues. In System 8.6 and later the Multiprocessing API Library is built into the System.
System 8.6 shipped with version 2.0 of the Multiprocessing API Library and associated CPU Plugin files installed in the Multiprocessing extensions folder.
System 9.0 shipped with version 2.1 of the Multiprocessing API Library installed into the System file directly. Associated CPU Plugin files are installed in the Multiprocessing extensions folder.
What special tools do I need for development?
After installing Universal Unterfaces 3.3 or later into your development system, you continue to use the same development tools you have always used. There are no special compilers or linkers to be used. All you add is a header file, Multiprocessing.h, to your source code then include the MPLibrary.stub file in your linker library list. Universal Unterfaces 3.3 or later are required for access to the Multiprocessing.h and the MPLibrary.stub link library.
How do I debug this stuff?
MacsBug version 6.6 is capable of debugging tasks much in the same way as it debugs within Mac itself. In addition, the MP API has debugging functions that allow you access to higher level task debugging information.
For source level debugging under CodeWarrior, you should contact Metrowerks for information and availability of the MP 2.0 compatible MetroNub. Metrowerks can be contacted by email at: support@metrowerks.com
Why am I getting an "out of memory" warning after the Finder starts?
If you get this message, you are running with the old v1.4 Multiprocessing API Library on a pre-8.6 System. The new integrated v2.0 library has eliminated the out of memory problems and is part of System 8.6 and later. It is no longer necessary to modify the Code Warrior extension MetroNub to increase its memory requirements.
What can tasks do?
In general tasks can execute any function accessible by your application. Tasks created using the MP API have the ability to access main memory allocated by any tasks created by the main application and to communicate with other tasks as well as the application. Tasks must adhere to the restrictions outlined below.
What are the restrictions on tasks and the application?
Tasks must not execute 68k code. Attempting to do so by calling through a UPP that entails a mixed mode switch to 68k will cause the task to be terminated.
Tasks must not call the Macintosh Toolbox directly. Tasks can access toolbox functions via the MPRemoteCall function, or by making the toolbox calls specifically allowed in the Multiprocessing Services documentation.
The application must not make MP API calls at interrupt time or from within a deferred task other than those specifically defined as interrupt-safe in the Multiprocessing Services documentation. Note that deferred tasks are defined in the Deferred Task Manager, they are not an MP API related concept.
How are tasks run?
Preemptive tasks, along with the Mac OS (blue) task, are inserted into a scheduling queue and are assigned to available processors. Tasks run preemptively. They run for a certain amount of time after which they will be interrupted and returned to the end of the scheduling queue. This way all tasks in the system can be assured fair access to the available processors. When a task waits on one of the resource objects, and that resource is not available, the task is immediately blocked and the next task on the scheduling queue is run. Blocked tasks are not returned to the scheduling queue until the object on which they are waiting becomes available. Blocked tasks incur no system overhead.
How many tasks should I create?
The number of tasks an application can create is not logically limited. Most applications will want to limit the creation of tasks that perform a given function to the number of available processors. As long as there are at least as many tasks performing work as there are available processors, maximum advantage of the system will be taken. Some problems are best decomposed into a fixed number of tasks, regardless of the number of processors. It is sometimes useful to have the main application perform some of the work also. This is especially true in applications that do not require the Multiprocessing API Library to be present. Task creation is expensive from a timing standpoint so you should avoid creating many tasks that run a short time then die off.
Do I need a multiprocessing system to use the MP API?
No. The Multiprocessing API Library is always available. This means that you can create preemptive tasks on a PowerPC platform, provided those tasks adhere to the restrictions described in the Multiprocessing Services 2.1 document.
How can I test MP-savvy applications?
Apple recommends testing the MP-savvy applications on two platforms: a uniprocessor Macintosh and a multiprocessor Macintosh. The application code can be identical in both cases, but the application may have dependencies or race conditions that are only visible on a multiprocessor system.
When can I get started?
You can start now. Under System 8.6 and later you to create and test applications on uniprocessor systems that will run without modification on real multiprocessing systems (assuming no programming errors of course).
When will hardware be available?
Dual processor hardware is currently available for the 9500 & 9600 machines in 180 & 200 Mhz speeds. Other system configurations will be available soon.
How will supporting the MP API impact my source base? What about 68K?
The MP API cannot be used on 68k machines. You can have a single source base but the 68k side will not be able to create preemptive tasks, and should behave as though the Multiprocessing API Library is not present. The PowerPC side should also be able to handle the situation where the Multiprocessing API Library is not present even though it is now a permanent part of the system. This retains backward compatibility. The same code can thus be used for both situations.
If an application requires PowerPC and is also willing to require the presence of the Multiprocessing API Library, then tasks can be created and executed regardless of the number of processors in the system. Tasks created by an application are distributed preemptively amongst the available processors, even if there is only one, so task-creating code will work on any type of PowerPC system.
What will happen to the MP API when Carbon API ships?
The MP API will run on all current and planned generations of the PowerPC-based Mac, namely, Mac OS 8.6 and later, the Carbon API under Mac OS 8.6 and later, and in Mac OS X.
How are the MP API and the Thread Manager related?
MP tasks are preemptive execution streams, and are implemented as kernel tasks in Mac OS 8/9 and Mac OS X. The task and thread APIs will remain different.
The Thread Manager API is supported in Mac OS 8/9 and Mac OS X, but there are no plans to extend it. Threads will continue to have the same cooperative scheduling model.
We are recommending that developers use the MP API to write applications that wish to take advantage of preemptive scheduling and multiprocessors, both on Mac OS 8 & 9 and Mac OS X. This API is fully supported in Mac OS 8 and beyond. It has been designed to map naturally into the Mac OS X tasking model.
Where can I find examples?
A set of example applications and sample code can be found in this software development kit. Source code for all applications is included where possible. In some cases, the source code is not available for Apple to release to developers.
How can I communicate with a task at interrupt time or from within a deferred task?
With the MP API 2.0 integrated multitasking support, communication can be achieved by simply using the MPSetEvent, MPSignalSemaphore, or MPNotifyQueue functions. The MPSetEvent and MPSignalSemaphore functions are always interrupt safe. MPNotifyQueue becomes interrupt safe when the subject queue has had notifications reserved for it. See MPSetQueueReserve in the Multiprocessing Services 2.1 document for details.
The rest of the Multiprocessing API Library is not interrupt safe and any attempt to call it at interrupt time or deferred task time will potentially cause a crash.
What kind of problems can I expect from tasks sharing memory?
Tasks should be careful about what memory they modify. It is not polite to modify memory being used by another task without communicating that fact to the other task. Modifying globals from within a task, or buffers pointed to by global variables should be avoided due to the potential for race conditions conflicts within your code. Semaphores are a safe way to allow read and write access to this type of data.
Tasks must not attempt to modify memory outside of the application address space. Although implementations may vary, the model is that each application runs in its own address space. The application's cooperative threads and any preemptive tasks created by the application share the same address space. Although the current Mac OS 8 & 9 implementation has all applications running in a global address space, this may change at any time. Applications that expect to run unchanged in Mac OS X must not violate this memory model.
I crash after calling MPTerminateTask(). Why?
MPTerminateTask() does not terminate a running task immediately. The task may continue to run for a short time while termination proceeds asynchronous to the MPTerminateTask call. Normal application cleanup techniques involve terminating all the tasks owned by the application and then disposing of all the semaphores, queues, memory, etc. that the tasks were using. Since the task doesn't really stop running straight away it can be using invalid data as the application starts deleting the shared resources, leading to catastrophic crashes. The proper way to avoid this situation is to provide a termination queue when you create a task, and wait on the queue immediately after terminating the task. Once you are notified, you can be sure that the task is no longer running. Alternatively your application can notify a task that it is about to be terminated and wait for the task to acknowledge the notification. The task should not use any more shared resources after it sends the acknowledgment.
I crash when my tasks run. Why?
One common problem is the task may not have enough stack space. Verify the stack assigned by MPCreateTask() is large enough to contain the deepest call chain in the preemptive task. In Mac OS 9, the default stack size created by MPCreateTask is 4K. If the preemptive task issues file system calls, a 32K or greater stack may be appropriate.
My preemptive task based app runs slower. Why?
Often the reason is the use of busy waiting loops within the application. A preemptive task should never loop continuously waiting for work. Instead it should wait on an MP object (a queue, semaphore, or event group) to await work. Likewise, the cooperative portion of the application should not busy wait. If the cooperative application enters a busy wait loop looking for preemptive tasks to return results, that activity interfers with the preemptive tasks and significantly lowers throughput. A busy wait within the cooperative part of the application also prevents other applications from gaining control. The cooperative portion of the application should include the test for the conclusion of preemptive task activity within its usual wait-next-event loop.
How do I get support for the MP API?
Apple computer is providing support for the MP API. You can contact Apple at <dts@apple.com>.